package org.d8s.magicapi.plugin.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.d8s.magicapi.pojo.OpenAuthAccountInfo;
import org.d8s.magicapi.util.SecurityUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.ssssssss.magicapi.interceptor.RequestInterceptor;
import org.ssssssss.magicapi.model.ApiInfo;
import org.ssssssss.magicapi.model.Constants;
import org.ssssssss.magicapi.model.JsonBean;
import org.ssssssss.script.MagicScriptContext;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.d8s.magicapi.util.EncryptConstants.START_PLUGIN_LOG_MSG;

/**
 * 接口验签
 *
 * @author 冰点
 * @date 2021-5-20 15:14:59
 */
@ConditionalOnProperty(prefix = "magic-plugin.openauth", name = "enable", havingValue = "true", matchIfMissing = false)
@Component
public class OpenAuthRequestInterceptor implements RequestInterceptor {

    private static final Logger log = LoggerFactory.getLogger(OpenAuthRequestInterceptor.class);
    /**
     * 对接方appId和密钥配置
     */
    @Value("${magic-plugin.openauth.accounts:[{\"appid\":\"23dsfs4dfsd234234\",\"appsecret\":\"AHD423SS23423$\",\"system\":\"oa系统\"}]}")
    private String accounts;

    private Map<String, OpenAuthAccountInfo> accountMap = new HashMap<>();

    @PostConstruct
    public void initIpLimitRequestInterceptor() {
        List<OpenAuthAccountInfo> list = JSON.parseObject(accounts, new TypeReference<List<OpenAuthAccountInfo>>() {
        });
        accountMap = list.stream().collect(Collectors.toMap(OpenAuthAccountInfo::getAppId, Function.identity(), (key1, key2) -> key1));
        log.info(START_PLUGIN_LOG_MSG, "接口验签", "magic-plugin.openauth.enable=false", "magic-plugin.openauth.accounts");
    }

    /**
     * 接口请求之前
     *
     * @param info    接口信息
     * @param context 脚本变量信息
     */
    @Override
    public Object preHandle(ApiInfo info, MagicScriptContext context, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Boolean isValid = isSignatureValid(context.getRootVariables());
        if (!isValid) {
            return new JsonBean(100, String.format("请求URL:[%s]，验签失败", info.getPath()));
        }
        return null;
    }

    private Boolean isSignatureValid(Map<String, Object> rootVariables) {
        try {
            Map<String, Object> body = (Map) rootVariables.get(Constants.VAR_NAME_REQUEST_BODY);
            Map<String, String> header = (Map<String, String>) rootVariables.get(Constants.VAR_NAME_HEADER);
            Map<String, String> pathParams = (Map<String, String>) rootVariables.get(Constants.VAR_NAME_PATH_VARIABLE);
            Map dataMap = new TreeMap<>();
            dataMap.putAll(body);
            dataMap.putAll(pathParams);
            String requestSign = header.get("sign");
            String appId = header.get("appId");
            if (accountMap.containsKey(appId)) {
                String secretKey = accountMap.get(appId).getAppSecret();
                String sign = SecurityUtil.createSign(dataMap, appId, secretKey);
                if (!requestSign.equals(sign)) {
                    log.info("验证签名不通过");
                    return false;
                }

            }
        } catch (Exception e) {
            log.error("验证签名失败rootVariables:[{}]", JSON.toJSONString(rootVariables));
            return false;

        }
        return false;
    }

    /**
     * 接口执行之后
     *
     * @param info    接口信息
     * @param context 变量信息
     * @param value   即将要返回到页面的值
     */
    @Override
    public Object postHandle(ApiInfo info, MagicScriptContext context, Object value, HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.debug("{} 执行完毕，返回结果:{}", info.getName(), value);
        return null;
    }


}
